home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
graphics
/
3dvect37.zip
/
POLY.INC
< prev
next >
Wrap
Text File
|
1994-06-22
|
114KB
|
3,722 lines
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Filename : Poly.inc
; Included from: 3D1.ASM, 3D2.ASM, 3D3.ASM
; Description : 3D xmode, polyfill and object handling routines
;
; Written by: John McCarthy
; 1316 Redwood Lane
; Pickering, Ontario.
; Canada, Earth, Milky Way (for those out-of-towners)
; L1X 1C5
;
; Internet/Usenet: BRIAN.MCCARTHY@CANREM.COM
; Fidonet: Brian McCarthy 1:229/15
; RIME/Relaynet: ->CRS
;
; Home phone, (905) 831-1944, don't call at 2 am eh!
;
; John Mccarthy would really love to work for a company programming Robots
; or doing some high intensive CPU work. Hint. Hint.
;
; Send me your protected mode source code!
; Send me your Objects!
; But most of all, Send me a postcard!!!!
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
public poly_fill ; fill polygon
public clear_fill ; clear screen
public initpages ; initialize video pages selected
public flip_page ; flip between video pages
public fakeline ; draw line in memory buffer
public fakelineg ; draw line in memory buffer (glenz)
public set_clip_absolute ; set clipping parameters - absolute
public set_clip_offset ; set clipping parameters - offset
public updvectors ; update vector positions/angles
public _update_window_camera ; update a windowing camera
public fastimultable ; fast imul table, dw 0-319 * 200
public clipped_line ; draw clipped line from dx,cx to ax,bx colour bp
public sort_list ; sort vector list
public drawvect ; draw vectors from command list
public look_at_it ; force camera to look at object
public calc_angles ; calculate angles between objects di,si
public calc_middle ; calculate angles of ebx,ecx,ebp into x,y
public get_displacement ; calculate difference between objects
public put_object ; put object si at ebx,ecx,ebp
public set_angle ; set object si to angle ebx,ecx,ebp
public set_shape ; set shape of object si to ax
public set_object_on ; set main object si to on
public set_object_off
public set_sub_object_on ; set sub-object on or off
public set_sub_object_off
public use_full_rotations ; set rotation style of object
public use_no_rotations
public set_to_hibitmap ; set object to be a static bitmap
public set_to_lobitmap
public set_bitmap_scaling ; set bitmap base scaling for this object
public search_next_available_object ; find next available object for use
public init_object ; initialize/clear object for use
public move_si ; move object si to ebx,ecx,ebp in di
public twist_si ; rotate object si to ebx,ecx,ebp in di
public twist_xonly ; rotate object si's x angle until = ebx, di = time
public twist_yonly ; rotate object si's y angle until = ecx, di = time
public twist_zonly ; rotate object si's z angle until = ebp, di = time
public stop_staring ; cancel look_at_si routine
public newfollow ; select new object for camera to follow
public where_si ; where will object si be in di frames?
public set_finall ; set xsfinal for object (location)
public set_finala ; set vxsfinal for object (angles)
public point_it ; point object si at object di
public point_dir ; point object si in direction it is moving instantly
public point_dir_time ; point object si in direction it is moving in di frames
public point_to ; point object si at location ebx,ecx,ebp
public set_speed ; calculate velocity based on angles
public point_time ; point obj di to bx,cx,bp in di frames
public time_to_point ; pre-cal point obj di to bx,cx,bp in di frames
public nullpalette ; only a null cross reference palette
public set_xref_palette ; set cross reference pal for object si to ebx
public fix_xangle ; test/correct camera x angle wrap-around
public fix_xangleq ; test/correct camera x angle wrap-around - when using joystick
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Clear_fill: Clears a block from active display page
;
; In:
; Regs=none
;
; Memory - usually these get set up during 3d vector plotting.
;
; lxupdate+0 = left x position of area to fill
; lxupdate+2 = top y position of area to fill
; lyupdate+0 = right x position of area to fill
; lyupdate+2 = bottom y position of area to fill
; use_clear - disable or enable screen clearing routine
; current_page - current offset of video memory for page of xmode, see xmode.asm
;
; Out:
; null
;
; Notes:
;
; This routine works only if borders of xclip land on even nybbles
; eg minimum x is 32 - works fine. but if minimum x is 37, this
; routine will clear all the way to 32 just the same.
;
; Routine was originally written by Matt Prichard. routine was then modified
; to clear using dwords, and clear to integer borders.
;
; example: call clear_fill ; duhhh...
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
clear_fill:
cmp use_clear,no
je tf_exit ; don't use clear routine
mov edi, current_page ; point to active vga page
out_8 sc_index, map_mask ; set up for plane select, should be already set
out_8 sc_data, all_planes ; write to all planes
if usefastborders eq no
if useborders eq yes
cld ; direction flag = forward
mov ax,lxupdate+0
mov bx,lxupdate+2
mov cx,lyupdate+0
mov dx,lyupdate+2
add ax,xcent ; center on screen
add bx,xcent
add cx,ycents1
add dx,ycentp1
and ax,0fff8h
and bx,0fff8h
add bx,7
cmp ax,cliplt ; clip to inside borders
jge s tf_noclip1
mov ax,cliplt
tf_noclip1:
cmp bx,xmaxxcent
jl s tf_noclip2
mov bx,cliprt
tf_noclip2:
cmp cx,cliptp
jge s tf_noclip3
mov cx,cliptp
tf_noclip3:
cmp dx,ymaxycent
jl s tf_noclip4
mov dx,ymaxycent
tf_noclip4:
mov lxupdate+0,ax
mov lxupdate+2,bx
mov lyupdate+0,cx
mov lyupdate+2,dx
cmp ax,bx
jg tf_exit ; nothing to do!
cmp cx,dx
jg tf_exit ; nothing to do!
mov ax,cx
mov bx,dx
sub bx,ax ; get y width
mov lyupdate+2,bx ; save in ypos2
else ; if not using borders update, clear entire
mov ax,cliptp ; area!
mov bx,ymaxycent
mov cx,cliplt ; use this if you want to change the
mov lxupdate+0,cx ; clipping parameters while the program is
mov cx,cliprt ; running, and if you want to have useborders
mov lxupdate+2,cx ; = no. the alternative code to this is the
mov dx,bx ; rept code below. it is faster but takes
sub dx,ax ; more memory.
mov lyupdate+2,dx
endif
and eax,0000ffffh
mov eax,[eax*4+fastimultable] ; mul y1 by bytes per line
add edi,eax ; di = start of line y1
mov dx,lxupdate ; dx = x1 (pixel position)
and edx,0000ffffh
shr edx,2 ; dx/4 = bytes into line
add edi,edx ; di = addr of upper-left corner
mov cx,lxupdate+2 ; cx = x2 (pixel position)
sub cx,lxupdate
and ecx,0000ffffh
shr ecx,3 ; cx/4 = bytes into line
inc ecx
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
mov dx,xactual/4 ; dx = di increment
sub dx,cx ; = screen_width-# planes filled
sub dx,cx
mov ebx,ecx ; bx = quick refill for cx
mov si,lyupdate+2 ; si = # of lines to fill
mov ax,background ; get fill color
push ax ; make 32 bit
shl eax,16
pop ax
shr ecx,1
shr ebx,1
jnc s tf_middle_loop2
align 4
tf_middle_loop1:
stosw
rep stosd ; fill in entire line
mov ecx, ebx ; recharge cx (line width)
add edi, edx ; point to start of next line
loopx si, tf_middle_loop1 ; loop until all lines drawn
jmp tf_exit ; reset update borders
align 16
tf_middle_loop2:
rep stosd ; fill in entire line, doubleword store
mov ecx, ebx ; recharge cx (line width)
add edi, edx ; point to start of next line
loopx si, tf_middle_loop2 ; loop until all lines drawn
tf_exit:
if useborders eq yes
mov ax,xupdate[0] ; and reset current update
mov lxupdate[0],ax
mov ax,xupdate[2]
mov lxupdate[2],ax
mov ax,yupdate[0]
mov lyupdate[0],ax
mov ax,yupdate[2]
mov lyupdate[2],ax
mov ax,xmaxs
mov bx,xmins1
mov cx,ymaxs
mov dx,ymins1
mov xupdate[0],ax
mov xupdate[2],bx
mov yupdate[0],cx
mov yupdate[2],dx
endif
ret ; exit
; this rept code generates a huge program that wipes the screen FAST
; only use this if you don't want to change the clipping parameters while
; the program is running.
else ; if useborders = no, clear entire area
mov ax,background ; get fill color
shl eax,16 ; make 32 bit
mov ax,background
i=0 ; this is a huge but fast method
rept (ymax-ymin)
j=0
rept (xmax-xmin)/4/4
mov d [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],eax
j=j+4
endm
if (xmax-xmin)/4/4 ne (xmax+8-xmin)/4/4
mov d [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi-2],eax
endif
i=i+1
endm
tf_exit:
ret
endif
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Poly_fill: Draws a filled polygon given table left and right addresses
;
; In:
; Regs=none
;
; Memory - these get set up by Fakeline routine
;
; colq - colour for polygon
; oney - top of polygon in table (maps to y location of screen)
; firstbyte[] - left side to begin draw
; lastbyte[] - right side to end draw
; current_page - current offset of video memory for page of xmode, see xmode.asm
;
; Out:
; null
;
; Notes:
; Call fakeline to define the edges of your polygon, then call here to fill it
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
pf_done:
pop eax
pf_outearly:
mov oney,1000 ; reset for next polygon call
ret
align 16
poly_fill:
; out_8 sc_index, map_mask ; set up for plane select
xor eax,eax
mov ebx,oney ; ax=y1
cmp bx,ymins
jl s pf_missub
cmp bx,ymaxs
jge pf_outearly
sub bx,ymins
mov ax,bx
pf_missub:
mov ebp,eax ; indexer to line
add ebp,ebp
add ax, cliptp
mov edi, current_page ; point to active vga page
mov eax,[eax*4+fastimultable] ; mul y1 by bytes per line
add edi,eax ; di = start of line y1
xor edx,edx
pf_more_lines:
push edi ; save right hand position
mov ax, [firstbyte+ebp]
cmp ax,xmaxs ; check if fill done
jge pf_done
xor ebx,ebx
mov bx,[lastbyte+ebp]
add ax,xcent
add bx,xcent
mov edx,eax ; dx = x1 (pixel position)
shr edx,2 ; dx/4 = bytes into line
add edi,edx ; di = addr of upper-left corner
mov ecx,ebx ; cx = x2 (pixel position)
shr ecx,2 ; cx/4 = bytes into line
cmp edx,ecx ; start and end in same band?
jg pf_exit ; skip if fakeline fails connection
je pf_one_band_only ; if so, then special processing
mov ah,colq ; get fill color
sub ecx,edx ; cx = # bands -1
mov esi,eax ; si = plane#(x1)
and esi,plane_bits ; if left edge is aligned then
jz s pf_l_plane_flush ; no special processing..
; draw "left edge" of 1-3 pixels...
out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
mov [edi], ah ; fill in left edge pixels
inc edi ; point to middle (or right) block
dec ecx ; reset cx instead of jmp pf_right
pf_l_plane_flush:
inc ecx ; add in left band to middle block
; di = addr of 1st middle pixel (band) to fill
; cx = # of bands to fill -1
pf_right:
mov esi,ebx ; get xpos2
and esi,plane_bits ; get plane values
cmp esi,0003 ; plane = 3?
je s pf_r_edge_flush ; hey, add to middle
; draw "right edge" of 1-3 pixels...
out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
mov esi,edi ; get addr of left edge
add esi,ecx ; add width-1 (bands) to point to top of right edge
dec esi
pf_right_loop:
mov [esi], ah ; fill in right edge pixels
dec ecx ; minus 1 for middle bands
jz s pf_exit ; uh.. no middle bands...
pf_r_edge_flush:
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
out_8 sc_data, all_planes ; write to all planes
mov dx, xactual/4 ; dx = di increment
sub edx, ecx ; = screen_width-# planes filled
mov al, ah ; colour is in high and low for stosw
pf_middle_loop:
shr ecx,1 ; use doubleword transfer
jnc s pf_ord
stosb ; if cx odd, store byte first
pf_ord:
rep stosw
pf_exit:
pop edi
mov d [firstbyte+ebp-2],03e803e8h ; reset table for next polygon (1000 doubleword)
mov d [lastbyte+ebp-2],0fc18fc18h ; -1000 doubleword
add ebp,2
add edi,xactual/4
jmp pf_more_lines
pf_one_band_only:
cmp ax, cliplt
jne s pf_nexit
cmp bx,ax
je s pf_exit
pf_nexit:
cmp ax, cliprt
je s pf_exit
mov esi,eax ; get left clip mask, save x1
and esi,plane_bits ; mask out row #
mov al,left_clip_mask[esi] ; get left edge mask
mov esi,ebx ; get right clip mask, save x2
and esi,plane_bits ; mask out row #
and al,right_clip_mask[esi] ; get right edge mask byte
out_8 sc_data, al ; clip for left & right masks
mov ah,colq ; get fill color
mov [edi], ah ; fill in pixels
jmp s pf_exit ; outa here, for this line
align 16
ss_done:
pop eax
ss_outearly:
mov oney,1000 ; reset for next polygon call
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; SS_dosteel: Fill polygon with a sine-waved texture. Implemented by the use
; of the "wavey" texture option.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
ss_dosteel:
; out_8 sc_index, map_mask ; set up for plane select
xor eax,eax
mov ebx,oney ; ax=y1
cmp bx,ymins
jl s ss_missub
cmp bx,ymaxs
jge ss_outearly
sub bx,ymins
mov ax,bx
ss_missub:
mov bl,colq ; yes, save colour offset and 16 block
mov steelc,bl
and steelc,0f0h ; save base offset of 16 colour block
shl bl,2 ; colour offset is *2 (small) *4 (large)
add bl,al ; make steel always constant
sub ebx,oney ;****** ; remove this line if you want sine textures to be "pegged" - eg stationary
and bl,03fh ; colour indexer (so sides look different)
mov steel ,bl
mov ebp,eax ; indexer to line
add ebp,ebp
add ax, cliptp
mov edi, current_page ; point to active vga page
mov eax,[eax*4+fastimultable] ; mul y1 by bytes per line
add edi,eax ; di = start of line y1
xor edx,edx
ss_more_lines:
push edi ; save right hand position
mov ax, [firstbyte+ebp]
cmp ax,xmaxs ; check if fill done
jge ss_done
xor ebx,ebx
mov bl,steel ; use steel texture?
mov dl,pf_updown[ebx]
add dl,steelc
mov colq,dl
inc bl
and bl,03fh ; 16 colours, 32 positions for steel texture
mov steel,bl
mov bx,[lastbyte+ebp]
add ax,xcent
add bx,xcent
mov edx,eax ; dx = x1 (pixel position)
shr edx,2 ; dx/4 = bytes into line
add edi,edx ; di = addr of upper-left corner
mov ecx,ebx ; cx = x2 (pixel position)
shr ecx,2 ; cx/4 = bytes into line
cmp edx,ecx ; start and end in same band?
jg ss_exit ; skip if fakeline fails connection
je ss_one_band_only ; if so, then special processing
mov ah,colq ; get fill color
sub ecx,edx ; cx = # bands -1
mov esi,eax ; si = plane#(x1)
and esi,plane_bits ; if left edge is aligned then
jz s ss_l_plane_flush ; no special processing..
; draw "left edge" of 1-3 pixels...
out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
mov [edi], ah ; fill in left edge pixels
inc edi ; point to middle (or right) block
dec ecx ; reset cx instead of jmp ss_right
ss_l_plane_flush:
inc ecx ; add in left band to middle block
; di = addr of 1st middle pixel (band) to fill
; cx = # of bands to fill -1
ss_right:
mov esi,ebx ; get xpos2
and esi,plane_bits ; get plane values
cmp esi,0003 ; plane = 3?
je s ss_r_edge_flush ; hey, add to middle
; draw "right edge" of 1-3 pixels...
out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
mov esi,edi ; get addr of left edge
add esi,ecx ; add width-1 (bands) to point to top of right edge
dec esi
ss_right_loop:
mov [esi], ah ; fill in right edge pixels
dec ecx ; minus 1 for middle bands
jz s ss_exit ; uh.. no middle bands...
ss_r_edge_flush:
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
out_8 sc_data, all_planes ; write to all planes
mov dx, xactual/4 ; dx = di increment
sub edx, ecx ; = screen_width-# planes filled
mov al, ah ; colour is in high and low for stosw
ss_middle_loop:
shr ecx,1 ; use doubleword transfer
jnc s ss_ord
stosb ; if cx odd, store byte first
ss_ord:
rep stosw
ss_exit:
pop edi
mov d [firstbyte+ebp-2],03e803e8h ; reset table for next polygon (1000 doubleword)
mov d [lastbyte+ebp-2],0fc18fc18h ; -1000 doubleword
add ebp,2
add edi,xactual/4
jmp ss_more_lines
ss_one_band_only:
cmp ax, cliplt
jne s ss_nexit
cmp bx,ax
je s ss_exit
ss_nexit:
cmp ax, cliprt
je s ss_exit
mov esi,eax ; get left clip mask, save x1
and esi,plane_bits ; mask out row #
mov al,left_clip_mask[esi] ; get left edge mask
mov esi,ebx ; get right clip mask, save x2
and esi,plane_bits ; mask out row #
and al,right_clip_mask[esi] ; get right edge mask byte
out_8 sc_data, al ; clip for left & right masks
mov ah,colq ; get fill color
mov [edi], ah ; fill in pixels
jmp s ss_exit ; outa here, for this line
align 16
; small steel texture, make sure to set shl bl,*1* before ss_missub:
;pf_updown db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
; db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
; large steel texture, make sure to set shl bl,*2* before ss_missub:
pf_updown db 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9
db 10,10,11,11,12,12,13,13,14,14,15,15
db 15,15,14,14,13,13,12,12,11,11,10,10
db 9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; WN_dowindow: Fill polygon with a mesh style texture. This plots only every
; other pixel.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
wn_done:
pop eax
wn_outearly:
mov oney,1000 ; reset for next polygon call
ret
align 16
wn_dowindow:
; out_8 sc_index, map_mask ; set up for plane select
xor eax,eax
mov ebx,oney ; ax=y1
cmp bx,ymins
jl s wn_missub
cmp bx,ymaxs
jge wn_outearly
sub bx,ymins
mov ax,bx
wn_missub:
mov ebp,eax ; indexer to line
add ebp,ebp
add ax, cliptp
mov edi, current_page ; point to active vga page
mov ebx,[eax*4+fastimultable] ; mul y1 by bytes per line
add edi,ebx ; edi = start of line y1
xor edx,edx
and eax,1
mov al,wn_zap[eax]
mov wn_zip,al
wn_more_lines:
xor wn_zip,0fh
push edi ; save right hand position
mov ax, [firstbyte+ebp]
cmp ax,xmaxs ; check if fill done
jge wn_done
xor ebx,ebx
mov bx,[lastbyte+ebp]
add ax,xcent
add bx,xcent
mov edx,eax ; dx = x1 (pixel position)
shr edx,2 ; dx/4 = bytes into line
add edi,edx ; di = addr of upper-left corner
mov ecx,ebx ; cx = x2 (pixel position)
shr ecx,2 ; cx/4 = bytes into line
cmp edx,ecx ; start and end in same band?
jg wn_exit ; skip if fakeline fails connection
je wn_one_band_only ; if so, then special processing
mov ah,colq ; get fill color
sub ecx,edx ; cx = # bands -1
mov esi,eax ; si = plane#(x1)
and esi,plane_bits ; if left edge is aligned then
jz s wn_l_plane_flush ; no special processing..
; draw "left edge" of 1-3 pixels...
mov dx,sc_data
mov al,left_clip_mask[esi]
and al,wn_zip
out dx,al
mov [edi], ah ; fill in left edge pixels
inc edi ; point to middle (or right) block
dec ecx ; reset cx instead of jmp wn_right
wn_l_plane_flush:
inc ecx ; add in left band to middle block
; di = addr of 1st middle pixel (band) to fill
; cx = # of bands to fill -1
wn_right:
mov esi,ebx ; get xpos2
and esi,plane_bits ; get plane values
cmp esi,0003 ; plane = 3?
je s wn_r_edge_flush ; hey, add to middle
; draw "right edge" of 1-3 pixels...
mov dx,sc_data
mov al,right_clip_mask[esi]
and al,wn_zip
out dx,al
mov esi,edi ; get addr of left edge
add esi,ecx ; add width-1 (bands) to point to top of right edge
dec esi
wn_right_loop:
mov [esi], ah ; fill in right edge pixels
dec ecx ; minus 1 for middle bands
jz s wn_exit ; uh.. no middle bands...
wn_r_edge_flush:
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
out_8 sc_data, wn_zip ; write to all planes
mov dx, xactual/4 ; dx = di increment
sub edx, ecx ; = screen_width-# planes filled
mov al, ah ; colour is in high and low for stosw
wn_middle_loop:
shr ecx,1 ; use doubleword transfer
jnc s wn_ord
stosb ; if cx odd, store byte first
wn_ord:
rep stosw
wn_exit:
pop edi
mov d [firstbyte+ebp-2],03e803e8h ; reset table for next polygon (1000 doubleword)
mov d [lastbyte+ebp-2],0fc18fc18h ; -1000 doubleword
add ebp,2
add edi,xactual/4
jmp wn_more_lines
wn_one_band_only:
cmp ax, cliplt
jne s wn_nexit
cmp bx,ax
je s wn_exit
wn_nexit:
cmp ax, cliprt
je s wn_exit
mov esi,eax ; get left clip mask, save x1
and esi,plane_bits ; mask out row #
mov al,left_clip_mask[esi] ; get left edge mask
mov esi,ebx ; get right clip mask, save x2
and esi,plane_bits ; mask out row #
and al,right_clip_mask[esi] ; get right edge mask byte
and al,wn_zip
out_8 sc_data, al ; clip for left & right masks
mov ah,colq ; get fill color
mov [edi], ah ; fill in pixels
jmp s wn_exit ; outa here, for this line
wn_zap db 5,0ah ;%0101,%1010
wn_zip db 0
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; DG_doglenz: Fill polygon with a glenz style vector. This routine fills
; up/down, not left/right like poly_fill. To set up the firstbyte
; and lastbyte tables for this routine, you must call fakelineg.
; Do not use fakeline, as fakeline fills left/right.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
dg_doglenz:
xor esi,esi
xor eax,eax
mov ebx,oney ; ax=x1
cmp bx,xmins
jl s dg_missub
cmp bx,xmaxs
jge wn_outearly
sub bx,xmins
mov ax,bx
dg_missub:
mov ebp,eax ; indexer to line
add ebp,ebp
add ax, cliplt
mov ebx,eax
; out_8 sc_index,map_mask
out_8 gc_index,read_map
dg_mnloop:
mov ax, [firstbyte+ebp]
cmp ax, ymaxs
jg s dg_doneall
mov si, [lastbyte+ebp]
sub si,ax
jz s dg_doneline
dg_kkil:
mov edi, current_page ; point to active vga page
add ax,ycent
movzx eax,ax
add edi,[eax*4+fastimultable] ; mul y1 by bytes per line
mov ecx,ebx ; dx = -len, bx = start, edi = screen (left)
mov eax,ebx
shr eax,2
add edi,eax
mov al, 1 ; map mask & plane select register
and cl, plane_bits ; get plane bits
shl al, cl ; get plane select value
out_8 sc_data, al ; select plane
mov al, cl
out_8 gc_index+1, al
xor ecx,ecx
mov cl,colq
mov ecx,[xreftable+ecx*4]
xor eax,eax
dg_mainloop:
mov al,[edi]
mov al,[ecx+eax]
mov [edi],al
add edi,xactual/4
dec esi
jnz s dg_mainloop
dg_doneline:
mov d [firstbyte+ebp-2],03e803e8h ; reset table for next polygon (1000 doubleword)
mov d [lastbyte+ebp-2],0fc18fc18h ; -1000 doubleword
add ebp,2
inc ebx
jmp dg_mnloop
dg_doneall:
mov oney,1000
mov leftmost,1000
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; DS_dostone: Fill polygon with a stone texture. Fill is performed
; up/down, not left/right like poly_fill. To set up the firstbyte
; and lastbyte tables for this routine, you must call fakelineG.
; Do not use fakeline, as fakeline fills left/right.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
ds_dostone:
xor esi,esi
xor eax,eax
mov ebx,oney ; ax=x1
cmp bx,xmins
jl s ds_missub
cmp bx,xmaxs
jge wn_outearly
sub bx,xmins
mov ax,bx
ds_missub:
mov ebp,eax ; indexer to line
add ebp,ebp
add ax, cliplt
mov ebx,eax
xor ecx,ecx
mov cl,colq
mov ecx,[stonetbl+ecx*4]
mov edx,[ecx]
add edx,ecx
add ecx,[ecx+4]
mov ds_ggh,edx
mov eax,oney
sub ax,xmins
jnl s ds_nol
neg eax
cmp ax,cliplt
jbe ds_llk
mov ax,cliplt
ds_llk:
add ecx,eax
ds_nol:
xor eax,eax
mov ax,cliplt
add ecx,eax
mov ds_yvar,ecx
mov ax,leftmost
add ax,ycent
jnl s ds_mnloop2
xor eax,eax
ds_mnloop2:
sub ds_ggh,eax
ds_mnloop:
mov dx, [firstbyte+ebp]
cmp dx, ymaxs
jg s ds_doneall
mov si, [lastbyte+ebp]
sub si,dx
jz s ds_doneline
ds_kkil:
mov edi, current_page ; point to active vga page
add dx,ycent
movzx edx,dx
add edi,[edx*4+fastimultable] ; mul y1 by bytes per line
mov ecx,ebx ; dx = -len, bx = start, edi = screen (left)
mov eax,ebx
shr eax,2
add edi,eax
mov al, 1 ; map mask & plane select register
and cl, plane_bits ; get plane bits
shl al, cl ; get plane select value
mov ecx,edx
out_8 sc_data, al ; select plane
mov eax,ds_yvar
movzx eax,byte ptr [eax]
add ecx,eax
add ecx,ds_ggh
ds_mainloop:
mov al,[ecx] ; the stone copy loop!
mov [edi],al
add edi,xactual/4
inc ecx
dec esi
jnz s ds_mainloop
ds_doneline:
mov d [firstbyte+ebp-2],03e803e8h ; reset table for next polygon (1000 doubleword)
mov d [lastbyte+ebp-2],0fc18fc18h ; -1000 doubleword
add ebp,2
inc ebx
inc ds_yvar
jmp ds_mnloop
ds_doneall:
mov oney,1000
mov leftmost,1000
ret
ds_ggh dd 0
ds_yvar dd 0
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Table of values for fast multiplication by screen width
; eg mov eax,[esi*4+fastimultable] ; eax = esi*320
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
fastimultable label dword
i=0
rept yactual
dd i*(xactual/4)
i=i+1
endm
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Hey! where is my postcard! see readme.doc file and send me that postcard!
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Initpages:
; In:
; Regs=none
; Out:
; Regs=none
;
; Notes: This is used to initialize the xmode paging - clears both screens
; and sets up the variable "current_page"
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
initpages:
pushw 0
call set_display_page
pushw 0
call set_active_page
pushw 0
call clear_vga_screen
pushw 1
call set_active_page
pushw 0
call clear_vga_screen
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Flip_page:
; In:
; Regs=none
; Out:
; Regs=none
;
; Notes: This is used to:
; 1) show the page we have been working on
; 2) set current_page to the other page (so we can work on it while the user
; looks at our other page)
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
flip_page:
if not pages eq 1
mov ax,display_page
xor al,1
push ax
call set_display_page
mov ax,active_page
xor al,1
push ax
call set_active_page
else
call sync_display
display "Note: Page flipping not allowed with only 1 page"
display " See equ.inc to select a mode with more than 1 page"
endif
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Fakeline: Draw a line in tables firstbyte,lastbyte, adjust oney if neccessary
;
; In:
; Regs=none
; Memory:
; x1 - x of line - cartisian format
; y1 - y of line
; x2 - x of line
; y2 - y of line
;
; Out:
; Regs=none
;
; Notes:
;
; Line is not drawn on screen but is drawn in memory tables. To use,
; tables must be clear, (default is always clear), just draw
; line around screen, in any order, then call poly_fill. The polygon will
; be drawn and checked in memory, then poly_fill will plop it on the current
; page. Poly_fill routine clears tables during plot so tables are ready for
; more lines and more polygons.
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
fakeline:
mov ax,y1
cmp y2,ax ; flip order of points if drawing up
jg s okorder
mov bx,x1
xchg bx,x2
xchg bx,x1
xchg ax,y2
mov y1,ax
okorder:
movsx eax,ax
cmp eax,oney
jge s nonewoney
mov oney,eax
nonewoney:
if useborders eq yes
cmp ax,yupdate+0 ; update borders for clearing routine
jge s up_no1
mov yupdate+0,ax
up_no1:
mov ax,y2
cmp ax,yupdate+2
jng s up_no2
mov yupdate+2,ax
up_no2:
mov dx,xupdate+0
mov cx,xupdate+2
mov ax,x1
mov bx,x2
cmp ax,dx
jge s up_no3
dec eax
mov xupdate+0,ax
mov edx,eax
inc eax
up_no3:
cmp bx,cx
jle s up_no4
inc ebx
mov xupdate+2,bx
mov ecx,ebx
dec ebx
up_no4:
cmp bx,dx
jge s up_no5
dec ebx
mov xupdate+0,bx
up_no5:
cmp ax,cx
jle s up_no6
inc eax
mov xupdate+2,ax
up_no6:
endif
mov ax,x2 ; ax=x
sub ax,x1
mov bx,y2 ; bx=y
sub bx,y1
jle sliver
mov rise,bx
movsx ebx,bx
shl eax,16
cdq
idiv ebx
mov ebp,eax ; ebp = slope*65536 (allows decimals)
mov ax,ymins
cmp y1,ax ; check if above screen
jge s li_abov1
sub ax,y1 ; ax = abs(difference of ymin-y1)
sub rise,ax ; dec counter
jle li_out ; line totally off screen
movsx eax,ax ; prepare for 32bit mul
imul ebp
shr eax,16 ; get top word
add x1,ax ; set new x1,y1 pair
mov ax,ymins
mov y1,ax
li_abov1:
movsx edx,x1
shl edx,16
mov cx,rise
mov ax,y1
movzx ebx,ax ; bx pointer first/lastbyte table
sub bx,ymins
add ebx,ebx ; bx now word
add eax,ecx ; will line go off bottom of screen?
cmp ax,ymaxs
jl s linep ; no...
sub ax,ymaxs ; yes, truncate cx for early exit
sub cx,ax
jle s li_out ; right off screen
linep:
mov eax,edx
mov di,xmins
mov si,xmaxs1
and ecx,0000ffffh
align 16
lineloop:
shr edx,16 ; main line drawing loop!!!
cmp dx,di
jg s nou
mov dx,di
jmp s noq
nou:
cmp dx,si
jl s noq
mov dx,si
noq:
cmp dx,firstbyte[ebx] ; fix first and lastbyte table
jge s ci1
mov firstbyte[ebx],dx
ci1:
cmp dx,lastbyte[ebx]
jng s ci2
mov lastbyte[ebx],dx
ci2:
add eax,ebp
mov edx,eax
add ebx,2
dec ecx
jnz s lineloop
li_out:
ret
align 16
sliver:
movzx ebx,y1 ; bx pointer first/lastbyte table
cmp bx,ymaxs
jge li_out
cmp bx,ymins ; clip to borders
jl li_out
sub bx,ymins
add ebx,ebx ; ebx now word
mov cx,x1
cmp cx,xmins
jge s nouq1
mov cx,xmins
nouq1:
cmp cx,xmaxs
jl s noqq1
mov cx,xmaxs1
noqq1:
cmp cx,firstbyte[ebx] ; fix first and lastbyte table
jg s ci1q1
mov firstbyte[ebx],cx
ci1q1:
cmp cx,lastbyte[ebx]
jng s ci6q1
mov lastbyte[ebx],cx
ci6q1:
mov cx,x2
cmp cx,xmins
jge s nouq2
mov cx,xmins
nouq2:
cmp cx,xmaxs
jl s noqq2
mov cx,xmaxs1
noqq2:
cmp cx,firstbyte[ebx] ; fix first and lastbyte table
jg s ci1q2
mov firstbyte[ebx],cx
ci1q2:
cmp cx,lastbyte[ebx]
jng s ci6q
mov lastbyte[ebx],cx
ci6q:
ret
align 16
fakelineg:
mov ax,x2
mov bx,y2
cmp bx,leftmost
jg fg_not1
mov leftmost,bx
fg_not1:
xchg y1,ax
xchg x1,bx
cmp ax,leftmost
jg fg_not2
mov leftmost,ax
fg_not2:
mov x2,ax
mov y2,bx
mov ax,y1
cmp y2,ax ; flip order of points if drawing up
jg s okorderg
mov bx,x1
xchg bx,x2
xchg bx,x1
xchg ax,y2
mov y1,ax
okorderg:
movsx eax,ax
cmp eax,oney
jge s nonewoneyg
mov oney,eax
nonewoneyg:
if useborders eq yes
cmp ax,yupdate+0 ; update borders for clearing routine
jge s up_no1g
mov yupdate+0,ax
up_no1g:
mov ax,y2
cmp ax,xupdate+2
jng s up_no2g
mov xupdate+2,ax
up_no2g:
mov dx,yupdate+0
mov cx,yupdate+2
mov ax,x1
mov bx,x2
cmp ax,dx
jge s up_no3g
dec eax
mov yupdate+0,ax
mov edx,eax
inc eax
up_no3g:
cmp bx,cx
jle s up_no4g
inc ebx
mov yupdate+2,bx
mov ecx,ebx
dec ebx
up_no4g:
cmp bx,dx
jge s up_no5g
dec ebx
mov yupdate+0,bx
up_no5g:
cmp ax,cx
jle s up_no6g
inc eax
mov yupdate+2,ax
up_no6g:
endif
mov ax,x2 ; ax=x
sub ax,x1
mov bx,y2 ; bx=y
sub bx,y1
jle sliverg
mov rise,bx
movsx ebx,bx
shl eax,16
cdq
idiv ebx
mov ebp,eax ; ebp = slope*65536 (allows decimals)
mov ax,xmins
cmp y1,ax ; check if above screen
jge s li_abov1g
sub ax,y1 ; ax = abs(difference of ymin-y1)
sub rise,ax ; dec counter
jle li_outg ; line totally off screen
movsx eax,ax ; prepare for 32bit mul
imul ebp
shr eax,16 ; get top word
add x1,ax ; set new x1,y1 pair
mov ax,xmins
mov y1,ax
li_abov1g:
movsx edx,x1
shl edx,16
mov cx,rise
mov ax,y1
movzx ebx,ax ; bx pointer first/lastbyte table
sub bx,xmins
add ebx,ebx ; bx now word
add eax,ecx ; will line go off bottom of screen?
cmp ax,xmaxs
jl s linepg ; no...
sub ax,xmaxs ; yes, truncate cx for early exit
sub cx,ax
jle s li_outg ; right off screen
linepg:
mov eax,edx
mov di,ymins
mov si,ymaxs
and ecx,0000ffffh
align 16
lineloopg:
shr edx,16 ; main line drawing loop!!!
cmp dx,di
jg s noug
mov dx,di
jmp s noqg
noug:
cmp dx,si
jl s noqg
mov dx,si
noqg:
cmp dx,firstbyte[ebx] ; fix first and lastbyte table
jge s ci1g
mov firstbyte[ebx],dx
ci1g:
cmp dx,lastbyte[ebx]
jng s ci2g
mov lastbyte[ebx],dx
ci2g:
add eax,ebp
mov edx,eax
add ebx,2
dec ecx
jnz s lineloopg
li_outg:
ret
align 16
sliverg: ret
movzx ebx,y1 ; bx pointer first/lastbyte table
cmp bx,xmaxs
jge li_outg
cmp bx,xmins ; clip to borders
jl li_outg
sub bx,ymins
add ebx,ebx ; ebx now word
mov cx,x1
cmp cx,ymins
jge s nouq1g
mov cx,ymins
nouq1g:
cmp cx,ymaxs
jl s noqq1g
mov cx,ymaxs1
noqq1g:
cmp cx,firstbyte[ebx] ; fix first and lastbyte table
jg s ci1q1g
mov firstbyte[ebx],cx
ci1q1g:
cmp cx,lastbyte[ebx]
jng s ci6q1g
mov lastbyte[ebx],cx
ci6q1g:
mov cx,x2
cmp cx,ymins
jge s nouq2g
mov cx,ymins
nouq2g:
cmp cx,ymaxs
jl s noqq2g
mov cx,ymaxs1
noqq2g:
cmp cx,firstbyte[ebx] ; fix first and lastbyte table
jg s ci1q2g
mov firstbyte[ebx],cx
ci1q2g:
cmp cx,lastbyte[ebx]
jng s ci6qg
mov lastbyte[ebx],cx
ci6qg:
ret
db " **** Hey, What are you doing ripping my code?! **** "
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Set_clip_absolute: Set clipping parameters - non cartisian
;
; In:
; AX - left for clip
; BX - top for clip
; CX - right for clip
; DX - bottom for clip
; Out:
; ?
;
; Notes:
; Set new clipping parameters where center is in middle of points ax,bx cx,dx
; where points are absolutes! eg (10,10) (50,50) would be a small window in
; the top corner of the screen.
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
set_clip_absolute:
mov si,cx ; calc center based on points
sub si,ax
shr si,1
add si,ax
mov di,dx
sub di,bx
shr di,1
add di,bx
sub ax,si ; now make points offset from center
sub cx,si
sub bx,di
sub dx,di ; fall through to set_clip_offset
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Set_clip_offset: Set clipping parameters - cartisian
;
; In:
; AX - left for clip - in cartisian format
; BX - top for clip
; CX - right for clip
; DX - bottom for clip
; SI - x of screen center - in cartisian format
; DI - y of screen center
; Out:
; ?
;
; Notes:
;
; Set new clipping parameters. does all pre-calculation for variables and
; resets oney, firstbyte and lastbyte table. SI,DI is center of screen. AX,BX
; and CX,DX are topleft and botright points to clip to. clipping will include
; minimum clip variables but will exclude maximum clip variables. eg -160,-100
; +160,+100, with center 160,100 are valid clip parameters. points are offsets
; from center, not absolutes! this allows you to have the camera looking to the
; left or right of where the pilot/plane is moving without having to change
; the camera angle. Note: this can only change slightly as distortion occures
; with too large an offset. Make sure to assemble the original file with the
; maximum Y size you will ever need so tables are set to correct size. You can
; never increase the total screen Y clipping beyond the original assembley
; restraints, but you can create any sized smaller windows.
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
set_clip_offset:
mov bp,dx
sub bp,bx
cmp bp,ymax-ymin ; check input parameters with assembley restraints
jg you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this
mov xmins,ax
mov xmaxs,cx
mov ymins,bx
mov ymaxs,dx
mov xcent,si
mov ycent,di
mov cliptp,di
add cliptp,bx
mov ycentp1,di
inc ycentp1
mov ycents1,di
dec ycents1
mov clipbt,di
add clipbt,dx
dec clipbt
mov cliplt,si
add cliplt,ax
mov cliprt,si
add cliprt,cx
dec cliprt
mov xmaxxcent,si
add xmaxxcent,cx
mov ymaxycent,di
add ymaxycent,dx
mov xmins1,ax
dec xmins1
mov xmaxs1,cx
dec xmaxs1
mov ymins1,bx
dec ymins1
mov ymaxs1,dx
dec ymaxs1
movsx eax,ax
movsx ebx,bx
movsx ecx,cx
movsx edx,dx
mov xmit,eax
mov xmat,ecx
mov ymit,ebx
mov ymat,edx
sub xmit,tolerance
add xmat,tolerance
sub ymit,tolerance
add ymat,tolerance
you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this:
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Updvectors: Update vector locations/angles (also does camera)
;
; In:
; null
; Out:
; null
;
; Notes:
; Update vector list based on traces_past
; I could have used a loop but shl ax,cl works faster
;
; What I am really doing is:
;
; for i = 1 to traces_past
; call updvectors2
; next i
;
; But instead I am shifting and adding (if bit present) for a faster method
; You get the idea right?
;
; This way, the slower the machine, the faster we move the objects to
; maintain a universal speed from 486dx66 machine to 386sx25 machine.
;
; This routines also handles the possibility that the camera is trying to
; lock on to a target object. I perform this operation here since this
; routine has control over the re-setting of traces_past.
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
updvectors:
mov ebx, traces_past
mov _old_traces_past,ebx
mov ebp,ebx
mov traces_past,0
mov edx,1
xor cl,cl
up_loop:
shr ebx,1
jnc not_call
call updvectors2
not_call:
add edx,edx ; dx = 1,2,4,8..
add cl,1 ; cx = 0,1,2,3,4,5,6...
or ebx,ebx ; all bits clear?
jne up_loop
cmp wfollow,no ; check if camera has reached follow object
je s nretest ; nothing to follow
cmp eyeacount,0
jne s nretest ; not reached yet
mov esi,wfollow ; looking at it, re-call newfollow
mov edi,oldspeed
cmp edi,ebp
ja newfollow ; re-calculate in case its accelerating
jmp just_look_at_it_now_instead_of_calculating
nretest:
ret
align 16
updvectors2: ; update vector list - shifted by cl
; and dec'ed by dx
i=0
rept maxobjects+1 ; generate unrolled update loop
local nupang, nuploc, nuder, nuuder
cmp acount+i*2,0
je nupang
sub acount+i*2,dx
ja nuder
mov acount+i*2,0 ; counter has expired with decimals!, now
mov ax,vxsfinal+i*2 ; use final position!
mov vxs+i*2,ax
mov ax,vysfinal+i*2
mov vys+i*2,ax
mov ax,vzsfinal+i*2
mov vzs+i*2,ax
jmp nupang ; outa here
align 16
nuuder:
mov lcount+i*2,0
mov eax,xsfinal+i*4 ; linear counter has expired with carry!
mov xs+i*4,eax
mov eax,ysfinal+i*4
mov ys+i*4,eax
mov eax,zsfinal+i*4
mov zs+i*4,eax
jmp nuploc
align 16
nuder:
mov ax,vxadds+i*2 ; update angles
shl eax,cl
add ax,vxs+i*2
mov vxs+i*2,ax
mov ax,vyadds+i*2
shl eax,cl
add ax,vys+i*2
mov vys+i*2,ax
mov ax,vzadds+i*2
shl eax,cl
add ax,vzs+i*2
mov vzs+i*2,ax
nupang:
cmp lcount+i*2,0
je nuploc
sub lcount+i*2,dx
jna nuuder ; go backward to avoid instruction buffer flush if successful
mov eax,xadds+i*4 ; update position
shl eax,cl
add eax,xs+i*4
mov xs+i*4,eax
mov eax,yadds+i*4
shl eax,cl
add eax,ys+i*4
mov ys+i*4,eax
mov eax,zadds+i*4
shl eax,cl
add eax,zs+i*4
mov zs+i*4,eax
nuploc:
i=i+1
endm
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; _Update_window_camera: Update the camera angles only
; In:
; _old_traces_past - IRQ controlled frame speed.
; Out: null
; Notes:
; This routine is for updating the position of any windowing camera. You can
; have as many windows as you want, just call this routine after you set a new
; window to update the camera movement for that specific viewport. The camera
; will be updated according to the speed set in _old_traces_past.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
_update_window_camera:
mov ebx,_old_traces_past
cmp eyeacount,0
je nupangeye
sub eyeacount,bx
ja nudereye
mov eyeacount,0 ; counter has expired with decimals!, now
mov ax,eyefinalax ; use final position!
mov eyeax,ax
mov ax,eyefinalay
mov eyeay,ax
mov ax,eyefinalaz
mov eyeaz,ax
jmp nupangeye ; outa here
align 16
nuudereye:
mov eyelcount,0
mov eax,eyefinalx ; linear counter has expired with carry!
mov eyex,eax
mov eax,eyefinaly
mov eyey,eax
mov eax,eyefinalz
mov eyez,eax
jmp nuploceye
align 16
nudereye:
mov ax,eyevxadds ; update angles
imul bx
add ax,eyeax
mov eyeax,ax
mov ax,eyevyadds
imul bx
add ax,eyeay
mov eyeay,ax
mov ax,eyevzadds
imul bx
add ax,eyeaz
mov eyeaz,ax
nupangeye:
cmp eyelcount,0
je nuploceye
sub eyelcount,bx
jna nuudereye ; go backward to avoid instruction buffer flush if successful
mov eax,eyexadds ; update position
imul ebx
add eax,eyex
mov eyex,eax
mov eax,eyeyadds
imul ebx
add eax,eyey
mov eyey,eax
mov eax,eyezadds
imul ebx
add eax,eyez
mov eyez,eax
nuploceye:
cmp wfollow,no ; check if camera has reached follow object
je s nretesteye ; nothing to follow
cmp eyeacount,0
jne s nretesteye ; not reached yet
mov esi,wfollow ; looking at it, re-call newfollow
mov edi,oldspeed
cmp edi,ebx
ja newfollow ; re-calculate in case its accelerating
jmp just_look_at_it_now_instead_of_calculating
nretesteye:
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Put_object: Set object location
; In:
; EBX - x point
; ECX - y point
; EBP - z point
; SI - object #
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
put_object:
movzx esi,si
mov xs[esi*4],ebx
mov ys[esi*4],ecx
mov zs[esi*4],ebp
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_angle: Set object angle
; In:
; BX - x angle (0-65536)
; CX - y angle
; BP - z angle
; SI - object #
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_angle:
movzx esi,si
mov vxs[esi*2],bx
mov vys[esi*2],cx
mov vzs[esi*2],bp
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_shape: Set object shape
; In:
; AX - shape of object (this later is used as an indexer in the objbase table)
; SI - object #
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_shape:
movzx esi,si
mov whatshape[esi*2],ax
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_object_on: Turn object on
; In:
; SI - object # to make visible
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_object_on:
movzx esi,si
or onoff[esi],mainobject_on
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_object_off: Turn object off
; In:
; SI - object # to stop drawing
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_object_off:
movzx esi,si
and onoff[esi],-1-mainobject_on
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_sub_object_on: Make angles and location refer to a sub object (arm, leg)
; In:
; SI - object # to designate as a sub-object
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_sub_object_on:
movzx esi,si
or onoff[esi],sub_object_on
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_sub_object_off: Make angles/locations/velicities refer to a sub object (arm, leg)
; In:
; SI - object # to un-designate as a sub-object
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_sub_object_off:
movzx esi,si
and onoff[esi],-1-sub_object_on
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Use_full_rotations: Make object free to rotate along any axis
; In:
; SI - object #
; Out=In
;
;Notes:
; This also clears the bitmap options below
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
use_full_rotations: ; set object to use full rotations
movzx esi,si
mov userotate[esi],full_rotations
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Use_no_rotations: Make object rigid along rotation axis (faster)
; In:
; SI - object #
; Out=In
;
; Notes:
; This also clears the bitmap options below
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
use_no_rotations: ; set object to have no rotation
movzx esi,si
mov userotate[esi],no_rotation
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_to_hibitmap: Make object a hi-res bitmap (like an explosion or something)
; In:
; SI - object #
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_to_hibitmap: ; set object to a static hi-res bitmap
movzx esi,si
mov userotate[esi],s_himap
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_to_lobitmap: Make object a lo-res bitmap (like an explosion or something)
; In:
; SI - object #
; Out=In
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_to_lobitmap: ; set object to a static lo-res bitmap
movzx esi,si
mov userotate[esi],s_lomap
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_bitmap_scaling: Set scaling factors for bitmaps (explosions)
; In:
; SI - object #
; BX - x scaling factor for bitmap
; CX - y scaling factor for bitmap
; Out=In
;
;Notes: This determines the Bitmaps "Size" in the virtual world.
; You do not have to make this smaller as the bitmap gets farther away,
; as this is done automatically.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
set_bitmap_scaling:
movzx esi,si
mov vxs[esi*2],bx ; bitmap scaling (gets added to bitx and bity)
mov vys[esi*2],cx ; bitmap scaling
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Search_next_available_object: Find an object which is not in use
; In:
; null
; Out:
; CF = 1 - no free objects
; CF = 0 - free object found
; ESI - # of free object to be defined as you please
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
search_next_available_object:
xor esi,esi
search_loop:
inc si
cmp si,maxobjects
je abort_srch
test onoff[esi],mainobject_on+sub_object_on
jnz search_loop
clc
ret
abort_srch:
stc ; carry set if no new object available (all are already used)
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Init_object: reset all parameters of an object.
; In:
; SI - # of object to reset
; Out:
; null
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
init_object:
movzx esi,si
xor eax,eax
mov userotate[esi],al
mov onoff[esi],al
mov xs[esi*4],eax
mov ys[esi*4],eax
mov zs[esi*4],eax
mov xadds[esi*4],eax
mov yadds[esi*4],eax
mov zadds[esi*4],eax
mov vxs[esi*2],ax
mov vys[esi*2],ax
mov vzs[esi*2],ax
mov vxadds[esi*2],ax
mov vyadds[esi*2],ax
mov vzadds[esi*2],ax
mov lcount[esi*2],ax
mov acount[esi*2],ax
mov xsfinal[esi*4],eax
mov ysfinal[esi*4],eax
mov zsfinal[esi*4],eax
mov vxsfinal[esi*2],ax
mov vysfinal[esi*2],ax
mov vzsfinal[esi*2],ax
mov palxref[esi],al
mov whatshape[esi*2],ax
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Move_si: Move object SI from wherever it is now to EBX,ECX,EBP in DI frames
; In:
; EBX - x location
; ECX - y location
; EBP - z location
; SI - # of object to move
; DI - # of frames to get there
; Out:
; null
;
; Notes:
; move is 32 bit, make sure high words of registers are set!
; time to get there is 16 bit. (if you need more, think! 65535 frames at
; 1/30 frames a sec is 15 minutes!)
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
move_si:
movzx esi,si
lea esi,[esi*4] ; si = dword
mov xsfinal[esi],ebx
mov ysfinal[esi],ecx
mov zsfinal[esi],ebp
sub ebx,xs[esi]
sub ecx,ys[esi]
sub ebp,zs[esi]
movzx edi,di
mov eax,ebx ; 32 bit moves
cdq
idiv edi
mov xadds[esi],eax
mov eax,ecx
cdq
idiv edi
mov yadds[esi],eax
mov eax,ebp
cdq
idiv edi
mov zadds[esi],eax
shr si,1 ; si = word
mov lcount[esi],di
shr si,1 ; restore original si
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Twist_si:Rotate object si from wherever it is now to ebx,ecx,ebp in di frames
; In:
; EBX - x angle
; ECX - y angle
; EBP - z angle
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
; Out:
; null
;
; Notes:
; Rotate is 32 bit, make sure high words of registers are set!
; Time to get there is 16 bit. Note: Although resulting angle will be
; 16 bit, input angle is 32 bit!. This allows you to rotate many times
; before coming to rest at a specified angle and also allows you to
; specify the direction of rotation. di specifies time to arrive.
; Final location is absolute, not relative to current angle.
;
; eg 00000100 is "rotate forwards until 100 degrees"
; 00078000 is "rotate 7 full rotations and come to rest at 32768 degrees"
; fffd9000 is "rotate backwards 2 rotations and come to rest at 9000h degrees"
; fffffff0 is "rotate backwards until 65520 degrees (-16)"
;
; Therefore, to reverse the direction of rotation (but maintain the final
; position) xor ebx,0ffff0000h (or ecx or ebp). bx is final position, but
; top word of ebx determines direction and number of turns to get there.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
twist_si:
movzx esi,si
shl esi,1 ; si = word, too many *2's
mov vxsfinal[esi],bx ; set final position when acount becomes 0
mov vysfinal[esi],cx
mov vzsfinal[esi],bp
sub bx,vxs[esi]
sub cx,vys[esi]
sub bp,vzs[esi]
movzx edi,di
mov eax,ebx ; 32 bit rotate
cdq
idiv edi
mov vxadds[esi],ax
mov eax,ecx
cdq
idiv edi
mov vyadds[esi],ax
mov eax,ebp
cdq
idiv edi
mov vzadds[esi],ax
mov acount[esi],di
shr esi,1 ; restore original si
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Twist_xonly:Rotate object si along single axis
; In:
; EBX - x angle
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
; Out:
; null
;
; Notes:
; Same as above...
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
twist_xonly:
movzx esi,si
mov vxsfinal[esi*2],bx ; set final position when acount becomes 0
sub bx,vxs[esi*2]
movzx edi,di
mov eax,ebx ; 32 bit rotate
cdq
idiv edi
mov vxadds[esi*2],ax
mov acount[esi*2],di
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Twist_yonly:Rotate object si along single axis
; In:
; ECX - y angle
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
; Out:
; null
;
; Notes:
; Same as above...
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
twist_yonly:
movzx esi,si
mov vysfinal[esi*2],cx ; set final position when acount becomes 0
sub cx,vys[esi*2]
movzx edi,di
mov eax,ecx ; 32 bit rotate
cdq
idiv edi
mov vyadds[esi*2],ax
mov acount[esi*2],di
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Twist_zonly:Rotate object si along single axis
; In:
; EBP - z angle
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
; Out:
; null
;
; Notes:
; Same as above...
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
twist_zonly:
movzx esi,si
mov vzsfinal[esi*2],bp ; set final position when acount becomes 0
sub bp,vzs[esi*2]
movzx edi,di
mov eax,ebp ; 32 bit rotate
cdq
idiv edi
mov vzadds[esi*2],ax
mov acount[esi*2],di
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Look_at_it: Set camera angles to point it toward the currently selected object
; Force camera to look at object wherelook
; In:
; null
; Out:
; modifes eyeax,eyeay
;
; Notes:
; This is called every frame before the Setsincose routine.
; Variables set by Newfollow routine and modifed by Updvectors.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
look_at_it:
mov esi,wherelook
cmp esi,no
je s noat ; get out, no object to look at (-1=flag)
mov edi,cameraobject
call calc_angles ; calculate difference between camera and obj
mov eyeay,bx ; this is where the camera should look...
mov eyeax,ax
noat:
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Calc_angles: Calculate angles between objects esi and edi.
; In:
; SI - # of object to look at
; DI - # of object to look from
; Out:
; AX - x angle
; BX - y angle
;
; Notes:
; Angles are from point of view of DI. Could be used for the camera but
; Newfollow does a better job. (now I know what your asking...Why does it
; do a better job right??? read on...)
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
calc_angles:
call get_displacement
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Calc_middle: Calculate angles to static point
; In:
; EBX - x location
; ECX - y location
; EBP - z location
; Out:
; AX - x angle
; BX - y angle
;
; Notes:
; Booga Boo
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
calc_middle:
push ecx ebx ebp
or ebp,ebp
jz lk_right_above ; check arctan(cx/0)
mov ecx,ebx ; first get z,x plane, (y angle)
mov eax,ebp
call arctan
lk_resume:
mov rise,ax ; save y angle
call cosign ; set up 32bit sin/cos multipliers
mov vycos,eax
mov ax,rise
call sign
pop ebp ebx ; now compute sqr(z^2+x^2) through y rotation
imul ebx ; use angle from calculation above
shrd eax,edx,14
mov edi,eax
mov eax,vycos
imul ebp
shrd eax,edx,14
add eax,edi ; di = new z = run
pop ecx ; cx = rise
or eax,eax
je s noaq
call arctan ; get ax=arctan(y/sqr(z^2+x^2))
mov bx,rise ; bx = y angle , ax = x angle
noaq:
ret
align 16
lk_right_above:
mov eax,16384
cmp ebx,0
jnl okdirax
neg eax
okdirax:
or ebx,ebx
jnz lk_resume ; check if camera x&z directly above object
pop ebp ebx ecx
mov ebx,16383 ; now find if looking straight up or straight down
or ebp,ebp
jl do_up
xchg ax,bx
ret
do_up:
mov bx,-16383
xchg ax,bx
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Get_displacement: figure out displacement between two objects
; In:
; SI - # of object to look at
; DI - # of object to look from
; Out:
; EBX - x distance (signed)
; ECX - y distance
; EBP - z distance
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
get_displacement:
and edi,0000ffffh ; faster than movzx (but dont quote me on it)
and esi,0000ffffh
mov ebx,xs[esi*4] ; get displacement of esi to edi
sub ebx,xs[edi*4]
mov ecx,ys[esi*4]
sub ecx,ys[edi*4]
mov ebp,zs[esi*4]
sub ebp,zs[edi*4]
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Stop_staring: Stop look_at_it from making camera follow currently selected object
; In:
; null
; Out:
; null
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
stop_staring:
mov wfollow,no ; cancel look_at_si re-lock-on sequence
mov wherelook,no ; disable look_at_si routine
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Newfollow: Get camera to follow an object around the screen
; In:
; SI - # of object to follow
; DI - time to get there (before lock on sequence)
; Out:
; modifes variables later used in Look_at_it
;
; Notes: Sometimes an object will be accelerating and the expected location
; may not be the actual location when the time comes. So newfollow is
; re-cursivly called at an accelerating rate until the target object is
; "captured".
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
newfollow:
mov wfollow,esi ; save in case object is accelerating
mov oldspeed,edi
mov wherelook,no ; disable look_at_si routine
or edi,edi ; test if time is zero
je just_look_at_it_now_instead_of_calculating
call where_si ; figure out where object si will end up
mov edi,oldspeed ; figure out where camera will end up
mov ax,eyelcount
cmp ax,di ; if di>lcount, shorten to lcount
ja s tx
mov di,ax
tx:
and edi,0000ffffh
mov eax,eyexadds
imul edi ; figure out where camera will be di*frames
add eax,eyex
sub ebx,eax ; get displacement to eye
mov eax,eyeyadds
imul edi
add eax,eyey
sub ecx,eax
mov eax,eyezadds
imul edi
add eax,eyez
sub ebp,eax
call calc_middle ; jump in middle of angle computation
mov eyefinalax,ax
mov eyefinalay,bx
mov di,bx
sub ax,eyeax ; get difference from where we are now
sub di,eyeay
add ax,followtol ; check if already looking at it
cmp ax,followtol*2
ja s calcit
add di,followtol
cmp di,followtol*2
jb just_look_at_it_now_instead_of_calculating
sub di,followtol
calcit:
sub ax,followtol
mov esi,oldspeed ; ax=x angle, di=y angle, si=# frames
cwd
push edx ; save sign extend
idiv si ; x/time
pop edx
or ax,ax
jne s n0
add dx,dx
mov ax,dx
inc ax ; ax = 1 or ax = -1
n0:
mov eyevxadds,ax
mov ax,di
cwd
push edx
idiv si ; y/time
pop edx
or ax,ax ; check if zero slope, must have some...
jne s n1
add dx,dx ; dx = fffe (-2) or 0
mov ax,dx
inc ax ; ax = 1 or ax = -1
n1:
mov eyevyadds,ax
mov eyeacount,si
shr oldspeed,1 ; if need to try again, time/2
mov ax,eyevzadds ; now adjust any z rotation into finalz
imul si
add ax,eyeaz
mov eyefinalaz,ax
ret
align 16
just_look_at_it_now_instead_of_calculating:
mov eax,wfollow
mov wherelook,eax ; already looking at object, now follow it
mov wfollow,no
mov eyeacount,0
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Where_si: Figure out where object SI will be in DI frames.
; In:
; SI - # of object to follow
; DI - time
; Out:
; EBX - x location
; ECX - y location
; EBP - z location
; SI - zSI
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
where_si:
and esi,0000ffffh
mov ax,lcount[esi*2]
or ax,ax
jne s nx
mov ebx,xs[esi*4] ; if object has no velocity, xs is position
mov ecx,ys[esi*4]
mov ebp,zs[esi*4]
ret
nx:
cmp ax,di ; if di>lcount, shorten to lcount
ja s nxq
mov di,ax
nxq:
and edi,0000ffffh
mov eax,xadds[esi*4] ; figure out where object will be di*frames
imul edi
add eax,xs[esi*4]
mov ebx,eax
mov eax,yadds[esi*4]
imul edi
add eax,ys[esi*4]
mov ecx,eax
mov eax,zadds[esi*4]
imul edi
add eax,zs[esi*4]
mov ebp,eax
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Drawvect: Draw vectors from sides list.
; In=Out=null
;
; Notes:
; Number of "sides" is "showing". Commands are in "textures" lists. All
; of this is set up by Load_points and Loadsides routines.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
dv_none2:
ret
drawvect:
cmp showing,0 ; no sides visible?
je s dv_none2
mov whichside,0 ; start at side 0
mov ebp,order[0] ; indexer to sides
dv_loop2:
test textures[ebp],line+himap+point+texture+glenz ; test if line, point, scalable bitmap or bitmapped texture
jnz dv_testit ; yes, do other routine
mov polytype,offset fakeline
dv_contq:
shl ebp,mult
mov dx,sides[ebp] ; first point is end flag
mov fex,dx
dv_loop1:
movzx esi,sides[ebp] ; get point, shl 1 not needed, pre-shl'ed
mov eax,[xp+esi]
mov ebx,[yp+esi]
mov x1,ax
mov y1,bx
mov si,[sides+ebp+2] ; get next point
cmp si,fex ; test if last = first, therefore done
pushf
mov eax,[xp+esi]
mov ebx,[yp+esi]
mov x2,ax
mov y2,bx
push ebp
call [polytype] ; draw next line
pop ebp
add ebp,2 ; bump to next pointer now
popf ; was this point equal to the first point?
jne s dv_loop1 ; no, draw more lines
mov esi,whichside ; set colour for this side
mov esi,order[esi]
mov al,b surfcolors[esi]
mov colq,al
xor ecx,ecx
mov cl,byte ptr textures[esi+1] ; use register which we can access low byte
and cl,7
call [polyjumps+ecx*4]
dv_return:
add whichside,4 ; bump bp to next block of points
mov ebp,whichside
mov ebp,order[ebp] ; get sort order
dec showing ; count for all sides
jne dv_loop2
dv_none:
ret
polyjumps dd offset poly_fill ; 0 ; solid fill
dd offset wn_dowindow ; 256 ; mesh
dd offset ss_dosteel ; 512 ; sine wave
dd offset 0 ; 512+256
dd offset dg_doglenz ; 1024 ; glenz vector
dd offset ds_dostone ; 1024+256 ; stone texture
dd offset 0 ; 1024+512
dd offset 0 ; 1024+512+256
dv_assinez:
mov polytype,offset fakelineg
jmp dv_contq
align 16
dv_testit:
mov ax,textures[ebp] ; perform command, return to dv_return
test eax,glenz
jnz dv_assinez
test eax,line
jnz dv_doline
test eax,point
jnz dv_dopoint
test eax,texture
jnz dv_texture
; draw bitmap at location x,y,z
shl ebp,mult
push eax ebp
movzx ebx,w [sides+4+ebp]
movzx ecx,w [sides+6+ebp]
movzx esi,[sides+2+ebp]
shl esi,2 ; si = dword
add ebx,bitx[esi]
add ecx,bity[esi] ; ebx,ecx = top corner of bitmap in 3d
mov eax,bitbase[esi]
mov bitmap,eax
mov si,[sides+0+ebp]
mov ebp,[zp+esi]
call make3d ; ebx,ecx = difference from center
pop ebp
movzx esi,[sides+0+ebp] ; get point
mov eax,[xp+esi]
mov ebp,[yp+esi]
sub ax,bx ; bx = x width/2 ax, bp = top corner
sub bp,cx ; cx = y height/2
if useborders eq yes
cmp bp,yupdate+0
jge s up_nq12
mov yupdate+0,bp
up_nq12:
cmp ax,xupdate+0
jge s up_nq32
mov xupdate+0,ax
up_nq32:
mov di,ax
mov dx,bp
endif
add ax,xcent
add bp,ycent
mov destx,ax
mov desty,bp
add bx,bx
add cx,cx
mov destwidth,bx
mov destheight,cx
if useborders eq yes
add di,bx
add dx,cx
cmp dx,yupdate+2
jng s up_nq42
mov yupdate+2,dx
up_nq42:
cmp di,xupdate+2
jng s up_nq22
mov xupdate+2,di
up_nq22:
endif
pop eax
test al,lomap-himap ; test to use 1/4 scale bitmap or full scale
jz s noq19
call xscale4
jmp dv_return
align 16
noq19:
call xscale2
noq7:
jmp dv_return
align 16
dv_dopoint:
mov dx,surfcolors[ebp] ; get colour of point
shl ebp,mult
movzx esi,[sides+ebp] ; get point x,y
mov ebx,[xp+esi]
mov ecx,[yp+esi]
cmp bx,xmins ; check if on screen
jl s noq7
cmp bx,xmaxs
jge s noq7
cmp cx,ymins
jl s noq7
cmp cx,ymaxs ; ymaxs1 if larger pixel
jge s noq7
mov edi, current_page ; point to active vga page
if useborders eq yes
cmp cx,yupdate+0
jge s up_no16
mov yupdate+0,cx
up_no16:
cmp bx,xupdate+0
jge s up_no36
mov xupdate+0,bx
up_no36:
cmp cx,yupdate+2
jng s up_no46
mov yupdate+2,cx
up_no46:
cmp bx,xupdate+2
jng s up_no26
mov xupdate+2,bx
up_no26:
endif
add bx,xcent
add cx,ycent
mov bp,dx ; save colour
mov si,cx
mov eax,[esi*4+fastimultable] ; get offset to start of line
mov cx, bx ; copy to extract plane # from
shr bx, 2 ; x offset (bytes) = xpos/4
add bx, ax ; offset = width*ypos + xpos/4
mov ax, map_mask_plane1 ; map mask & plane select register
and cl, plane_bits ; get plane bits
shl ah, cl ; get plane select value
out_16 sc_index, ax ; select plane
and ebx,0000ffffh
mov ax,bp ; re-get colour
mov [edi+ebx],al ; draw pixel, low is top, high is bottom
; add edi,xactual/4
; mov [edi+ebx],ah ; draw larger bullet/pixel (high byte)
; if drawing larger pixel, change above code to this!
; cmp cx,ymaxs1
; jge s noa7
jmp dv_return
align 16
; handle line command from drawvect, uses clipped_line routine
dv_doline:
mov edi,ebp ; save...
mov bp,surfcolors[ebp]
shl edi,mult
movzx esi,[sides+edi] ; get first point
mov edx,[xp+esi]
mov ecx,[yp+esi]
mov si,[sides+edi+2] ; second point indexer
mov eax,[xp+esi] ; now load up second point
mov ebx,[yp+esi]
call clipped_line
jmp dv_return ; return to drawvect
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Clipped_line: Draw clipped line in cartesian format from (dx,cx) to (ax,bx)
; using colour bp
; In:
; AX - x2
; BX - y2
; CX - y1
; DX - x1
; BP - Colour
; current_page - current screen start location
; Out:null
;
; Similar routine to fakeline but faster, more accurate and draws directly
; to screen (current_page). Routine updates clearing borders (if used)
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
clipped_line:
cmp bx,cx ; flip order of points if drawing up
jg s r_okorder
xchg bx,cx
xchg ax,dx
r_okorder:
mov x1,dx
mov y1,cx
mov x2,ax
mov y2,bx
if useborders eq yes
cmp cx,yupdate+0 ; update borders for clearing routine
jg s r_up_no1
mov yupdate+0,cx
r_up_no1:
cmp bx,yupdate+2
jng s r_up_no2
mov yupdate+2,bx
r_up_no2:
mov bx,ax
mov ax,dx
mov dx,xupdate+0
mov cx,xupdate+2
cmp ax,dx
jge s r_up_no3
dec ax
mov xupdate+0,ax
mov dx,ax
inc ax
r_up_no3:
cmp bx,cx
jle s r_up_no4
inc bx
mov xupdate+2,bx
mov cx,bx
dec bx
r_up_no4:
cmp bx,dx
jge s r_up_no5
dec bx
mov xupdate+0,bx
r_up_no5:
cmp ax,cx
jle s r_up_no6
inc ax
mov xupdate+2,ax
r_up_no6:
mov ax,x2 ; ax=x
sub ax,x1
mov bx,y2 ; bx=y
sub bx,y1
elseif not useborders eq yes
sub ax,dx
sub bx,cx
endif
mov dx,bp
mov colq,dl
mov dx,ymaxs
cmp y1,dx
jge cl_return
mov rise,bx
movsx ebx,bx
or ebx,ebx
jne s r_nsliver
mov bx, y1
cmp bx, ymins ; draw sliver, avoid divide by zero
jl cl_return
cmp bx, dx ; dx = ymax
jge cl_return
add bx,ycent
movzx esi,bx
mov eax,[esi*4+fastimultable] ; get offset to start of line
mov edi, current_page
add edi, eax ; edi = starting y location
mov rise,1
mov dx, x1 ; from here...
mov si, x2 ; ..to here
cmp si,xmins
jge s u_nou3
mov si,xmins
u_nou3:
cmp si,xmaxs
jl s u_noq3
mov si,xmaxs1
u_noq3:
jmp r_splint ; re-enter draw later in code
align 16
r_nsliver:
shl eax,16
cdq
idiv ebx
mov ebp,eax ; ebp = slope*65536 (allows decimals)
mov ax,ymins
cmp y1,ax ; check if above screen
jge s r_li_abov1
sub ax,y1 ; ax = abs(difference of ymin-y1)
sub rise,ax ; dec counter
jle cl_return ; line totally off screen
movsx eax,ax ; prepare for 32bit mul
imul ebp
shr eax,16 ; get top word
add x1,ax ; set new x1,y1 pair
mov ax,ymins
mov y1,ax
r_li_abov1:
mov bx,y1 ; bx distance from top of screen
add bx,ycent
movzx esi,bx ; calculate screen address
mov eax,[esi*4+fastimultable] ; get offset to start of line
mov edi, current_page
add edi,eax ; edi = starting y location
movsx edx,x1
shl edx,16
mov cx,rise
mov ax,y1
add ax,cx ; will line go off bottom of screen?
cmp ax,ymaxs
jl s r_linep ; no...
sub ax,ymaxs ; yes, truncate cx for early exit
sub rise,ax
jle cl_return
r_linep:
mov eax,edx
and ecx,0000ffffh
mov esi,edx
shr esi,16
cmp si,xmins
jge s r_nou
mov si,xmins
r_nou:
cmp si,xmaxs
jl s r_noq
mov si,xmaxs1
align 16
r_noq:
r_lineloop:
add eax,ebp ; main line drawing loop!!! (for lines)
mov edx,eax
shr edx,16
r_splint:
cmp dx,xmins
jge s u_nou
mov dx,xmins
cmp dx,si
je r_mis
u_nou:
cmp dx,xmaxs
jl s u_noq
mov dx,xmaxs1
cmp dx,si
je r_mis
u_noq:
push edx edi ebp eax ; save for next line
cmp dx,si
jle s r_no_switch
xchg dx,si
r_no_switch:
add dx,xcent
add si,xcent
mov ax,dx
mov bx,si
mov x2,si
movzx edx,dx
shr edx,2 ; dx/4 = bytes into line
add edi,edx ; di = addr of upper-left corner
movzx ecx,bx ; cx = x2 (pixel position)
shr ecx,2 ; cx/4 = bytes into line
cmp dx,cx ; start and end in same band?
je rf_one_band_only ; if so, then special processing
sub cx,dx ; cx = # bands -1
mov esi,eax ; si = plane#(x1)
and esi,plane_bits ; if left edge is aligned then
jz s rf_l_plane_flush ; no special processing..
; draw "left edge" of 1-3 pixels...
out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
mov al,colq ; get fill color
mov [edi], al ; fill in left edge pixels
inc edi ; point to middle (or right) block
dec ecx ; reset cx instead of jmp s rf_right
rf_l_plane_flush:
inc ecx ; add in left band to middle block
; di = addr of 1st middle pixel (band) to fill
; cx = # of bands to fill -1
rf_right:
mov esi,ebx ; get xpos2
and esi,plane_bits ; get plane values
cmp esi,0003 ; plane = 3?
je s rf_r_edge_flush ; hey, add to middle
; draw "right edge" of 1-3 pixels...
out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
mov esi,edi ; get addr of left edge
add esi,ecx ; add width-1 (bands) to point to top of right edge
dec esi
mov al,colq ; get fill color
rf_right_loop:
mov [esi], al ; fill in right edge pixels
dec ecx ; minus 1 for middle bands
jz rf_exit ; uh.. no middle bands...
rf_r_edge_flush:
; di = addr of upper left block to fill
; cx = # of bands to fill in (width)
out_8 sc_data, all_planes ; write to all planes
mov edx, xactual/4 ; dx = di increment
sub edx, ecx ; = screen_width-# planes filled
mov al, colq ; get fill color
mov ah, al ; colour is in high and low for stosw
push ax ; make colour 32 bit
shl eax,16
pop ax
rf_middle_loop:
shr ecx,1 ; use doubleword transfer
jnc s rf_ord
stosb ; if cx odd, store byte first
rf_ord:
rep stosw
jmp s rf_exit ; outa here, for this line
rf_one_band_only:
mov esi,eax ; get left clip mask, save x1
and esi,plane_bits ; mask out row #
mov al,left_clip_mask[esi] ; get left edge mask
mov esi,ebx ; get right clip mask, save x2
and esi,plane_bits ; mask out row #
and al,right_clip_mask[esi] ; get right edge mask byte
out_8 sc_data, al ; clip for left & right masks
mov al, colq ; get fill color
mov [edi], al ; fill in pixels
rf_exit:
pop eax ebp edi esi ; pop screen left address
r_mis:
add edi, xactual/4
dec rise
jg r_lineloop
cl_return:
ret
align 16
dv_texture:
;movzx ebx,surfcolors[ebp]
;mov eax,bitbase[ebx*4]
;mov textured_bitmap_offset,eax
;
;shl ebp,mult
;
;mov bx,[sides+0+ebp]
;mov ax,xp[ebx]
;mov bx,yp[ebx]
;mov xorg+0,ax
;mov yorg+0,bx
;
;mov bx,[sides+2+ebp]
;mov ax,xp[ebx]
;mov bx,yp[ebx]
;mov xorg+2,ax
;mov yorg+2,bx
;
;mov bx,[sides+4+ebp]
;mov ax,xp[ebx]
;mov bx,yp[ebx]
;mov xorg+4,ax
;mov yorg+4,bx
;
;mov bx,[sides+6+ebp]
;mov ax,xp[ebx]
;mov bx,yp[ebx]
;mov xorg+6,ax
;mov yorg+6,bx
;
;call draw_texture_map ; not implemented yet!
jmp dv_return
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Sort_list: Bubble sort for sides
; In=Out=null
;
; Sort is not perfect since many sides can use the same point.
; If this point is the first point in the list and therefore zeds[] uses
; the same point for sort, the routine may mess up when plotting at some
; acute angles. If you ever notice this, you are way too picky. You
; could fix this by adjusting the load_sides routine to search for the
; closest z point.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
align 16
minusd equ offset zeds - offset order
sort_list:
mov esi,showing
cmp esi,3 ; if only one surface, exit
jbe qke
shl esi,2 ; esi = dword
add esi,o order
align 16
nextcx:
sub esi,4 ; point to last word in order[] table
mov ebp,esi ; set order pointer
mov ebx,d [esi] ; get order[si]
mov edi,esi
add edi,minusd
mov ecx,d [edi] ; get zeds[si]
align 16
nextdx:
sub edi,4
sub ebp,4
cmp ecx,d [edi] ; zeds is point from side, should be max z
jle s donothing
xchg ecx,d [edi] ; don't flip entire side, just indexers to it
xchg ebx,d [ebp]
donothing:
cmp ebp,o order ; check bp = 0
jne s nextdx
mov [esi + minusd],ecx
mov [esi],ebx
cmp esi,o order + 4
jne s nextcx
qke:
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_finall: routine sets the "final" variables for perfect updvectors calculations
; In:
; SI = object #
; Out: null
;
; This fixes the small (and I mean small) discrepancies when the raster count
; does not divide evenly into the objects rotational or linear count.
; Eg lcount =1001, raster count = 10, object should move 1001 units but gets
; moved 100*10 (only moves 1000 units). This makes absolutly sure that an
; object moved to a location in DI frames will actually get to that exact
; position! (regardless of machine speed or raster speed or number of objects
; on screen or whatever!).
;
; Call this routine after setting new anglular or linear velocities. There is
; no need to call this routine if you are going to set a position or location
; but xxxfinal must be set if you are going to change the velocities. The
; variables xxxfinal[] are used by updvectors to set the final position/angle
; of an object after the counters lcount and acount have expired. If you know
; the final position/angle of your object, set these yourself. But if
; you only want to move the object and don't care where it will end up, call
; this routine and the final position/angle will be calculated for you.
; Note: xxxfinal variables will only be used if the raster count does not
; divide evenly into the angle/linear count.
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
set_finall:
movzx esi,si ; do this in case user is lazy...
movzx ecx,lcount[esi*2] ; final position = speed * time
mov eax,xadds[esi*4] ; xsfinal = xadds * lcount + position
imul ecx ; you get the idea right?
add eax,xs[esi*4]
mov xsfinal[esi*4],eax
mov eax,yadds[esi*4]
imul ecx
add eax,ys[esi*4]
mov ysfinal[esi*4],eax
mov eax,zadds[esi*4]
imul ecx
add eax,zs[esi*4]
mov zsfinal[esi*4],eax
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_finala: Routine sets the "final" variables for perfect updvectors calculations
; In:
; SI = object #
; Out: null
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
set_finala:
movzx esi,si ; do this in case user is lazy...
mov cx,acount[esi*2] ; final angle = angular velocity * time
mov ax,vxadds[esi*2] ; vxsfinal = vxadds * acount + angle
imul cx
add ax,vxs[esi*2]
mov vxsfinal[esi*2],ax
mov ax,vyadds[esi*2]
imul cx
add ax,vys[esi*2]
mov vysfinal[esi*2],ax
mov ax,vzadds[esi*2]
imul cx
add ax,vzs[esi*2]
mov vzsfinal[esi*2],ax
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Point_it: Point object SI at object DI
; In:
; SI = object # to point
; DI = target object
; Out:
; vxs[esi*2]=AX= x angle (in case you need it)
; vys[esi*2]=BX= y angle
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
point_it:
push esi edi
xchg si,di ; xchange so user doesn't get confused
push edi
call calc_angles
pop edi
movzx edi,di
mov vxs[edi*2],ax
mov vys[edi*2],bx
pop edi esi
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Point_dir: Point object SI in direction it is moving
; In:
; SI = object # to point
; xadds[esi*4] = direction object is moving
; yadds[esi*4] = " "
; zadds[esi*4] = " "
; Out:
; vxs[esi*2]=AX= x angle (in case you need it)
; vys[esi*2]=BX= y angle
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
point_dir:
movzx esi,si
mov ebx,xadds[esi*4]
mov ecx,yadds[esi*4]
mov ebp,zadds[esi*4]
shl ebx,4 ; * whatever to get some decimal accuracy
shl ecx,4
shl ebp,4
mov edi,esi ; xchange so user doesn't get confused
push edi
call calc_middle
pop esi
mov vxs[esi*2],ax
mov vys[esi*2],bx
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Point_dir_time: Point object SI in direction it is moving in DI frames
; In:
; SI = object # to point
; DI = time to arrive at angle
; xadds[esi*4] = direction object is moving
; yadds[esi*4] = " "
; zadds[esi*4] = " "
; Out:
; vxadds[esi*2]= x angle counter
; vyadds[esi*2]= y angle counter
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
point_dir_time:
movzx edi,di
push edi
movzx esi,si
mov ebx,xadds[esi*4]
mov ecx,yadds[esi*4]
mov ebp,zadds[esi*4]
shl ebx,4 ; * whatever to get some decimal accuracy
shl ecx,4
shl ebp,4
mov edi,esi ; xchange so user doesn't get confused
push edi
call calc_middle
pop esi
pop edi
mov vxsfinal[esi*2],ax ; set final position when acount becomes 0
mov vysfinal[esi*2],bx
sub ax,vxs[esi*2]
cwd
idiv di
mov vxadds[esi*2],ax
sub bx,vys[esi*2]
mov ax,bx
cwd
idiv di
mov vyadds[esi*2],ax
mov acount[esi*2],di
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Point_to: Point object SI at location EBX,ECX,EBP.
; In:
; SI = object # to point
; EBX = x location
; ECX = y location
; EBP = z location
; Out:
; vxs[esi*2]=AX= x angle (in case you need it)
; vys[esi*2]=BX= y angle
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
point_to:
mov di,si ; xchange so user doesn't get confused
movzx edi,di
push edi
sub ebx,xs[edi*4] ; get displacement of esi to edi
sub ecx,ys[edi*4]
sub ebp,zs[edi*4]
call calc_middle
pop esi
mov vxs[esi*2],ax
mov vys[esi*2],bx
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_speed: "Move object in direction it is pointing"
; Set speed of object si to ebp*angle, then set lcount to di
;
; In:
; SI = object # to set speed of
; EBP = signed speed (10000 is good, 1 is dead slow, 10000000 is light speed, fffff000 = 4096 reverse)
; DI = how long to hold this speed for (not in calculation, only "when to stop")
; Out - ?
;
; Notes:
; xadds= (- cosx * siny) * ebp
; yadds= (- sinx) * ebp
; zadds= (cosx * cosy) * ebp
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
set_speed:
movzx esi,si
mov lcount[esi*2],di
mov ax,vxs[esi*2]
neg ax
push eax
call cosign
mov ecx,eax ; cx = cos x
pop eax
call sign
neg eax
imul ebp ; set y speed
shrd eax,edx,14
mov yadds[esi*4],eax
mov ax,vys[esi*2]
neg ax
push eax
call cosign
mov edx,eax ; dx = cos y
pop eax
call sign
mov ebx,edx ; save because imul trashes dx
imul ecx ; ax = sy * cx
shrd eax,edx,14 ; shr eax,14 compensates for cos decimals
imul ebp
shrd eax,edx,14
neg eax
mov xadds[esi*4],eax
mov eax,ebx
imul ecx
shrd eax,edx,14
imul ebp
shrd eax,edx,14
mov zadds[esi*4],eax
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Point_time: Point object SI at location EBX,ECX,EBP, in DI frames (DI = time)
; In:
; EBX = x location
; ECX = y location
; EBP = z location
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
; Out:
; null
;
; Notes:
; This could also be used for the camera, but if you are going to
; point the camera at an object, call newfollow instead. Newfollow
; allows for when the object is moving - newfollow will track the
; object as it moves and even if it accelerates! The camera
; movement/turning must have high resolution or the viewer will
; notice a "glitch" or "jump".
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
point_time:
call time_to_point
; add ebx,000010000h ; do this if you want more than one rotation
; add ecx,000020000h ; along a selected axis.
; add ebp,0fffc0000h
jmp twist_si ; twist object to this location in di frames!
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Time_to_point: Calculate timed angles in preparation for roll.
; In:
; EBX = x location
; ECX = y location
; EBP = z location
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
; Out:
; EBX - x angle (sign extended for direction of roll)
; ECX - y angle
; EBP - z angle
; SI - # of object to spin/twist/roll...
; DI - # of frames to get there
;
; Notes:
; Output is ready for Twist_si routine. But you can add high words to the
; output in order to get it to roll more than 1 rotation. See example above
; The direction for rotation is defined by the closest angle.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
time_to_point:
push edi esi edi esi ebp ecx ebx
call where_si ; find out where object will be in di frames
pop eax ; get x location to look at
sub ebx,eax ; get displacement of where it will be to where
neg ebx ; it should point
pop eax ; get y location to look at
sub ecx,eax
neg ecx
pop eax ; get z location to look at
sub ebp,eax
neg ebp
pop edi esi ; notice reverse order for calc_middle!
call calc_middle
pop esi ; pop object number
pop edi ; pop time
movzx esi,si
push ax bx ; save x angle,yangle
sub ax,vxs[esi*2]
sub bx,vys[esi*2]
movsx ecx,bx ; set sign for rotations
movsx ebx,ax
pop cx bx ; cx = y angle, bx = x angle
mov ax,vzadds[esi*2] ; figure out z (calc_middle wont)
imul di
add ax,vzs[esi*2]
movsx ebp,ax ; angles are sign extended for direction of rotation!!!
ret
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Default/Null cross referencing palette: eg 1=1, 7=7, 221=221...
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
nullpalette:
i=0
rept 256
db i
i=i+1
endm
align 16
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set_xref_palette: Set cross referencing palette for object si
; In:
; ESI = object #
; BL = selected cross referencing palette number (eg 0,1,2,3,4)
;
; Notes:
; Each object can have its own colour scheme by setting the cross reference
; palette to re-direct the actual colours to a new set of colours. The xref
; palette doesn't have to be 256 bytes long, it only needs to re-direct the
; colours that your selected object has.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
set_xref_palette:
movzx esi,si
mov palxref[esi],bl
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Fix_xangle: Force x angle of camera to remain within range ± 16384
; In=Out=none
;
; Notes: This routine can be called once every frame. The purpose of this
; routine is to prevent the camera x angle from making the camera turn
; upsidedown. All the routine will do is, when the x angle goes out-of-range,
; this will turn the y angle 180degrees and also turn the x angle 180degrees.
; The camera x angular velocity will also be negated.
;
; This doesn't look that good when the joystick is being used, but it is
; is really for when the camera is in auto-movement mode.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
fix_xangle:
mov ax,eyeax
add ax,16384
cmp ax,32768
ja fixxangle
ret
fixxangle:
add eyeay,32768
add eyeax,32768
add eyeaz,32768
neg eyeax
neg eyevxadds
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; This fix routine looks great with the joystick, but it is more like a brick
; wall than a correct solution to x angle inversion.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
fix_xangleq:
mov ax,eyeax
add ax,16384
cmp ax,32768
ja fixxangleq
ret
fixxangleq:
cmp eyeax,0
jl fixqqq
mov eyeax,16383
ret
fixqqq:
mov eyeax,-16383
ret